/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.dao.impl;

import cn.easyplatform.dao.DaoException;
import cn.easyplatform.dao.SeqDao;
import cn.easyplatform.dao.utils.DaoUtils;
import cn.easyplatform.transaction.jdbc.JdbcTransactions;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class DefaultSeqDaoImpl extends AbstractDao implements SeqDao {

    /**
     * @param ds
     */
    public DefaultSeqDaoImpl(DataSource ds) {
        super(ds);
    }

    @Override
    public void delete(String name) {
        PreparedStatement pstmt = null;
        Connection conn = null;
        try {
            if (log.isDebugEnabled())
                log.debug("delete->{}", name);
            conn = ds.getConnection();
            conn.setAutoCommit(false);
            pstmt = conn
                    .prepareStatement("delete from sys_serial_info where keyvalue=?");
            pstmt.setString(1, name);
            pstmt.execute();
            conn.commit();
        } catch (SQLException ex) {
            try {
                conn.rollback();
            } catch (Exception e) {
            }
            throw new DaoException("dao.access.seq.delete", ex, name);
        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
            }
            DaoUtils.closeQuietly(pstmt);
            DaoUtils.closeQuietly(conn);
        }
    }

    @Override
    public Long nextVal(String name) {
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Connection conn = null;
        try {
            if (log.isDebugEnabled())
                log.debug("nextval->{}", name);
            conn = ds.getConnection();
            //conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
            conn.setAutoCommit(false);
            pstmt = conn
                    .prepareStatement("select keyvalue,incvalue from sys_serial_info where keyname=?");
            pstmt.setString(1, name);
            rs = pstmt.executeQuery();
            Long nextId;
            if (rs.next()) {
                nextId = rs.getLong(1) + rs.getInt(2);
                DaoUtils.closeQuietly(pstmt, rs);
                pstmt = conn
                        .prepareStatement("update sys_serial_info set keyvalue=? where keyname=?");
                pstmt.setLong(1, nextId);
                pstmt.setString(2, name);
                pstmt.executeUpdate();
            } else {
                DaoUtils.closeQuietly(pstmt, rs);
                rs = null;
                nextId = 1L;
                pstmt = conn
                        .prepareStatement("insert into sys_serial_info(keyname,keyvalue,incvalue) values(?,?,?)");
                pstmt.setString(1, name);
                pstmt.setLong(
                        2, nextId);
                pstmt.setInt(3, 1);
                pstmt.executeUpdate();
            }
            conn.commit();
            if (log.isDebugEnabled())
                log.debug("nextval->{}:{}", name, nextId);
            return nextId;
        } catch (SQLException ex) {
            try {
                conn.rollback();
            } catch (Exception e) {
            }
            if (log.isErrorEnabled())
                log.error("nextval", ex);
            throw new DaoException("dao.access.seq.nextval", ex, name);
        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
            }
            DaoUtils.closeQuietly(pstmt, rs);
            DaoUtils.closeQuietly(conn);
        }
    }


    @Override
    public void reset(String name, long value) {
        PreparedStatement pstmt = null;
        Connection conn = null;
        try {
            if (log.isDebugEnabled())
                log.debug("reset->{}", name);
            conn = ds.getConnection();
            conn.setAutoCommit(false);
            pstmt = conn
                    .prepareStatement("update sys_serial_info set keyvalue=? where keyname=?");
            pstmt.setLong(1, value);
            pstmt.setString(2, name);
            pstmt.executeUpdate();
            conn.commit();
        } catch (SQLException ex) {
            try {
                conn.rollback();
            } catch (Exception e) {
            }
            throw new DaoException("dao.access.seq.reset", ex, name);
        } finally {
            try {
                conn.setAutoCommit(true);
            } catch (SQLException e) {
            }
            DaoUtils.closeQuietly(pstmt);
            DaoUtils.closeQuietly(conn);
        }
    }

    @Override
    public List<Object[]> getList() {
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        Connection conn = null;
        try {
            conn = JdbcTransactions.getConnection(ds);
            pstmt = conn
                    .prepareStatement("select keyname,keyvalue,incvalue from sys_serial_info order by keyname");
            rs = pstmt.executeQuery();
            List<Object[]> data = new ArrayList<>();
            while (rs.next()) {
                data.add(new Object[]{rs.getString(1), rs.getLong(2), rs.getInt(3)});
            }
            return data;
        } catch (SQLException ex) {
            throw new DaoException("dao.biz.query.error", ex, "sys_serial_info");
        } finally {
            DaoUtils.closeQuietly(pstmt, rs);
            DaoUtils.closeQuietly(conn);
        }
    }
}

